/******************************************************************************************************
Copyright (C) 2012 Mestrelab Research S.L. All rights reserved.

This file is part of the MNova scripting toolkit.

Authorized users of MNova Software may use this file freely, but this file is provided AS IS
with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE.
*****************************************************************************************************/

/*globals mainWindow, NMRSpectrum, print*/
/*jslint plusplus: true, indent: 4*/

function NMRSpectrumUtils() {
	"use strict";
}

NMRSpectrumUtils.prototype = {};

NMRSpectrumUtils.prototype.overlayCompatibility = function (aSpecs) {
	"use strict";
	var specUtils = new NMRSpectrumUtils();
	return specUtils.sameNucleus(aSpecs) && specUtils.sameDim(aSpecs);
};

NMRSpectrumUtils.prototype.sameNucleus = function (aSpecs) {
	"use strict";
	var nmrSpec1, nmrSpec, firstDim, i, j;

	if (!aSpecs.length) {
		return false;
	}

	nmrSpec1 = aSpecs[0];
	if (!nmrSpec1.isValid()) {
		return false;
	}
	firstDim = nmrSpec1.dimCount;

	for (i = 1; i < aSpecs.length; i++) {
		nmrSpec = aSpecs[i];
		if (!nmrSpec.isValid()) {
			return false;
		}

		for (j = 1; j <= firstDim; j++) {
			if (nmrSpec.nucleus(j, false) !== nmrSpec1.nucleus(j, false)) {
				return false;
			}
		}
	}

	return true;
};

NMRSpectrumUtils.prototype.sameDim = function (aSpecs) {
	"use strict";
	var nmrSpec1, nmrSpec, i;

	if (!aSpecs.length) {
		return false;
	}

	nmrSpec1 = aSpecs[0];
	if (!nmrSpec1.isValid()) {
		return false;
	}

	for (i = 1; i < aSpecs.length; i++) {
		nmrSpec = aSpecs[i];
		if (nmrSpec.dimCount !== nmrSpec1.dimCount) {
			return false;
		}
	}

	return true;
};

/** Returns a scale containing all the zoom scales of the spectrum List. The returned object has the atributtes: min, max. Always in PPMs
* boolean aZoomLimits indicates if the boundaries are taking the current vertical axis (S axis in the case of stacked spectra) or the Y Axis (f1 axis
* in the case of 2D stacked spectra, intensity in the case of 1D spectra)
*/
NMRSpectrumUtils.prototype.scaleBoundaries = function (aDim, aSpecs, aZoomLimits) {
	"use strict";
	var i, nmrSpec, min, max, sLimits, v, units, axisDim,
		maximum = -1e9,
		minimum = 1e9,
		boundaries = {},
		specUtils = new NMRSpectrumUtils();

	if (!specUtils.sameDim(aSpecs)) {
		boundaries.min = minimum;
		boundaries.max = maximum;

		return boundaries;
	}

	for (i = 0; i < aSpecs.length; i++) {
		nmrSpec = aSpecs[i];
		if (nmrSpec.isValid() && nmrSpec.dimCount >= aDim) {
			if (aZoomLimits) {
				sLimits = nmrSpec.getZoomLimits();
			} else {
				sLimits = nmrSpec.getScaleLimits();
			}

			if (nmrSpec.dimCount === 1) {
				units = nmrSpec.getProperty("axes.horizontal.units");
				axisDim = 1;
				min = sLimits.fromX;
				max = sLimits.toX;
			} else {
				if (aDim === 2) {
					axisDim = 2;
					min = sLimits.fromX;
					max = sLimits.toX;
					units = nmrSpec.getProperty("axes.horizontal.units");
				} else {
					axisDim = 1;
					min = sLimits.fromY;
					max = sLimits.toY;
					units = nmrSpec.getProperty("axes.vertical.units");
				}
			}

			min = nmrSpec.unitsToUnits(units, "ppm", min, axisDim);
			max = nmrSpec.unitsToUnits(units, "ppm", max, axisDim);

			if (min > max) {
				v = max;
				max = min;
				min = v;
			}

			minimum = minimum <= min ? minimum : min;
			maximum = maximum >= max ? maximum : max;
		}
	}

	boundaries.min = minimum;
	boundaries.max = maximum;

	return boundaries;
};

/** Returns a scale containing the full scales of the spectrum List. The returned object has the atributtes: min, max. Always in PPMs.
*/
NMRSpectrumUtils.prototype.fullScaleBoundaries = function (aDim, aSpecs) {
	"use strict";

	var i, nmrSpec, min, max, v, axisDim,
		maximum = -1e9,
		minimum = 1e9,
		fullBoundaries = {},
		specUtils = new NMRSpectrumUtils();

	if (!specUtils.sameDim(aSpecs)) {
		fullBoundaries.min = minimum;
		fullBoundaries.max = maximum;

		return fullBoundaries;
	}

	for (i = 0; i < aSpecs.length; i++) {
		nmrSpec = aSpecs[i];
		if (nmrSpec.isValid() && nmrSpec.dimCount >= aDim) {
			axisDim = (nmrSpec.dimCount === 1 || (nmrSpec.dimCount === 2 && aDim === 1)) ? 1 : 2;

			min = nmrSpec.unitsToUnits("pt", "ppm", 0, axisDim); //firstPtToUnits;
			max = nmrSpec.unitsToUnits("pt", "ppm", nmrSpec.count(axisDim) - 1, axisDim); //lastPtToUnits;

			if (min > max) {
				v = max;
				max = min;
				min = v;
			}
			minimum = minimum <= min ? minimum : min;
			maximum = maximum >= max ? maximum : max;
		}
	}
	fullBoundaries.min = minimum;
	fullBoundaries.max = maximum;

	return fullBoundaries;
};

NMRSpectrumUtils.prototype.getMaxNumberPoints = function (aDim, aSpecs) {
	"use strict";
	var i, nmrSpec, pt, fullLimits, sSpec, max, min,
		specUtils = new NMRSpectrumUtils(),
		m = 0,
		s = 0;

	if (!aSpecs.length || !specUtils.sameDim(aSpecs)) {
		return 0;
	}

	for (i = 0; i < aSpecs.length; i++) {
		nmrSpec = aSpecs[i];
		pt = nmrSpec.count(aDim);
		if (pt > m) {
			m = pt;
			s = i;
		}
	}

	//s is the spectrum with the highest number of points
	fullLimits = specUtils.fullScaleBoundaries(aDim, aSpecs);
	if (s >= 0 && s < aSpecs.length) {
		sSpec = aSpecs[s];
		if (sSpec.isValid()) {
			max = sSpec.unitsToUnits("ppm", "pt", fullLimits.max, aDim);
			min = sSpec.unitsToUnits("ppm", "pt", fullLimits.min, aDim);

			return Math.round(Math.abs(max - min));
		}
	}

	return 0;
};

//test
NMRSpectrumUtils.UtilsTest = function () {
	"use strict";
	var i, nmrSpc, specUtils, a, b, c, limits, fullLimits, f,
		aPageItems = mainWindow.activeDocument.selection(),
		specs = [];

	for (i = 0; i < aPageItems.length; i++) {
		nmrSpc = new NMRSpectrum(aPageItems[i]);
		if (nmrSpc.isValid()) {
			specs.push(nmrSpc);
		}
	}

	specUtils = new NMRSpectrumUtils();
	a = specUtils.sameDim(specs);
	print("sameDim", a);

	b = specUtils.sameNucleus(specs);
	print("sameNucleus", b);

	c = specUtils.overlayCompatibility(specs);
	print("overlayCompatibility", c);

	limits = specUtils.scaleBoundaries(1, specs);
	print("scaleBoundaries", limits.min, limits.max);

	fullLimits = specUtils.fullScaleBoundaries(1, specs);
	print("fullScaleBoundaries", fullLimits.min, fullLimits.max);

	f = specUtils.getMaxNumberPoints(1, specs);
	print("getMaxNumberPoints", f);
};
